Skip to content

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Oct 5, 2025

This is a complete implementation of https://github.com/lampepfl/papers/pull/155. It consists of the following major parts:

Let fresh caps in field types contribute to class captures

A fresh in the capture set of a class field now causes a fresh
to be added to the capture set of every instance of that class.

This caused 18 failures in stdlib of which 2 were significant (the rest was deprecated stuff). So far, we make
this compile with the @caps.unsafe.untrackedCaptures annotation. #24137 explains what would be needed
to fix this in a safer way.

Add prefixes to fresh caps and relate class and field fresh caps

Fresh created in classes now carry a prefix referring to the this of the class. The prefix gets mapped
by TypeMaps, including asSeenFrom. We establish a "covers" relation between a fresh for an object and a fresh for one of its fields. We use the same relation for subsumption.

Example:

class A:
  val f: Ref^ = Ref()
val a: A^{cap1} = A()

Here the type of a.f is A^{a.cap2}. Furthermore cap1, the cap captured by the type of a, both covers and subsumes a.cap2.

Make sure that private fields with inferred types don't capture a fresh cap

Fields contribute fresh caps to the class. The problem is what to do with capsets in inferred types of fields. These pose problems of separate compilation. We already demand explicit declarations of capsets of non-private fields. We need to also demand an explicit declaration when a private field has an inferred capset that is not otherwise accounted for in the capset of the enclosing class. That condition can be checked post-cc, when all capsets are known. I.e. it is checked at the same time as when we check non-private fields.

The prefix is mapped as a normal type. It determines whether
the hidden set allows to add new elements. ThisType and NoPrefix
prefixes allow it, other prefixes forbid it.

The pathRoot and ccOwner of a FreshCap now depend on the prefix.
Also: add another test that demonstrates some  behavior relating to default
parameters.

Also: Rename a test so that we don't accidentally get the test file.
In general, it's a bad idea to use a source file name in the compiler code
for a test since we often get the wrong file when loading it into the editor.
Was cap.rd before, which was a left-over of the old model.
Refine the isField test in SymUtils to exclude non-members and phantom symbols
@odersky odersky requested a review from a team as a code owner October 5, 2025 17:47
@odersky odersky added the area:capabilities Issues tied with scala.caps.Capabilities label Oct 5, 2025
A fresh in the capture set of a class field now causes a fresh
to be added to the capture set of every instance of that class.
 - Drop the assertion and handle the case of empty overlap
 - At the same time, avoid the empty overlap by taking complete
   instead of direct footprints.

Also: Improve printing of FreshCap prefixes
Needed for use checking, since if we just take the leftmost prefix
we sometimes end up with a `this`.
@odersky odersky changed the title Let FreshCaps in field types contribute to class captures Implement FreshCap Handling for Classes and Objects Oct 8, 2025
Private fields in publicly accessible classes that contribute fresh caps to their
class still need an explicitly declared type, so that separate compilation can work.
@odersky odersky added area:experimental:cc Capture checking related and removed area:capabilities Issues tied with scala.caps.Capabilities labels Oct 8, 2025
@natsukagami natsukagami self-requested a review October 8, 2025 15:07
@natsukagami
Copy link
Contributor

natsukagami commented Oct 8, 2025

Similar to #24137 (comment) I could patch the stdlib in the same way to completely avoid untrackedCaptures: natsukagami@f638614

I made a PR: dotty-staging#73

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:experimental:cc Capture checking related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants